package topic

import (
	"context"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/service/backend/common/utils/pointy"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/internal/utils/errorhandler"
	"mall/service/forum/rpc/types/forum"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetReplyListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetReplyListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetReplyListLogic {
	return &BackendGetReplyListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetReplyListLogic) BackendGetReplyList(in *forum.BackendPostListReq) (*forum.PostListResp, error) {
	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			if orderBy.Field == "id" {
				orderBys = append(orderBys, model.ForumPostColumns.PostID+order)
			}
		}
	}

	var stati string
	var postType string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			switch filterBy.Field {
			case "status":
				stati = filterBy.In
			case "type":
				postType = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	filterMap := make(map[string]map[string][]any)
	if in.Ids != nil {
		if vals := modelx.UniqueInterfaces(strings.TrimSpace(*in.Ids), 64); len(vals) > 0 {
			filterMap[model.ForumPostColumns.PostID] = map[string][]any{
				"in": vals,
			}
			restricted = true
		}
	}
	if !restricted {
		page = in.Page
		pageSize = in.PageSize
	}

	var statusIsSet bool
	if in.ForumId != nil && *in.ForumId >= uint64(globalkey.ForumPostTypeReply) { // 指定版块的回复
		filterMap[model.ForumPostColumns.ForumID] = map[string][]any{
			"equalTo": []any{*in.ForumId},
		}
	} else { // 默认版块的回复
		filterMap[model.ForumPostColumns.ForumID] = map[string][]any{
			"moreThanOrEqualTo": []any{globalkey.ForumPostTypeReply},
		}
	}
	switch postType {
	case "1": // 回复（待审核）
		filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
			"equalTo": []any{globalkey.StatusPending},
		}
		statusIsSet = true
	case "2": // 回复（已通过）
		filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
			"equalTo": []any{globalkey.StatusApproved},
		}
		statusIsSet = true
	case "3": // 回复（已驳回）
		filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
			"equalTo": []any{globalkey.StatusRejected},
		}
		statusIsSet = true
	case "4": // 回复（用户已删除）
		filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
			"equalTo": []any{globalkey.StatusDeleted},
		}
		statusIsSet = true
	}

	if !statusIsSet {
		statusIn := modelx.UniqueInterfaces(stati, 32)
		statusMap := make(map[string][]any)
		if len(statusIn) > 0 {
			statusMap["in"] = statusIn
		}
		if in.Status != nil && *in.Status > 0 {
			statusMap["equalTo"] = []any{*in.Status - 1}
		}
		filterMap[model.ForumPostColumns.PostStatus] = statusMap
	}

	if in.TopicId != nil {
		filterMap[model.ForumPostColumns.TopicID] = map[string][]any{
			"equalTo": []any{*in.TopicId},
		}
	}
	if in.ParentId != nil {
		filterMap[model.ForumPostColumns.ParentID] = map[string][]any{
			"equalTo": []any{*in.ParentId},
		}
	}
	if in.AuthorId != nil {
		filterMap[model.ForumPostColumns.PostAuthorID] = map[string][]any{
			"equalTo": []any{*in.AuthorId},
		}
	}
	if in.Sticky != nil {
		filterMap[model.ForumPostColumns.Sticky] = map[string][]any{
			"equalTo": []any{*in.Sticky},
		}
	}

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	} else {
		orderBy = model.ForumPostColumns.PostModifiedDate + " DESC"
	}
	res, count, err := l.svcCtx.Post.GetList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp := &forum.PostListResp{
		Total: uint64(count),
	}

	if len(res) > 0 {
		var pids []any
		var tids []any
		for _, v := range res {
			pids = append(pids, v.PostID)
			tids = append(tids, v.TopicID)
		}

		mediaFilterMap := make(map[string]map[string][]any)
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"in": pids,
		}
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": []any{globalkey.AttachmentLogTypeForumPost},
		}
		var orderBy string = model.ForumAttachmentRelationshipColumns.AttachmentThumbnail + " DESC," +
			model.ForumAttachmentRelationshipColumns.AttachmentOrder
		mediaList, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{
			"pageSize": uint64(len(pids) * 3),
			"orderBy":  orderBy,
		}, -1, mediaFilterMap)
		if err != nil {
			return nil, err
		}

		idMediaMap := make(map[uint64][]*forum.ForumMediaInfo)
		if len(mediaList) > 0 {
			for _, v := range mediaList {
				idMediaMap[v.ObjectID] = append(idMediaMap[v.ObjectID], &forum.ForumMediaInfo{
					Uid:       pointy.GetPointer(v.AttachmentRelationshipID),
					Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
					Uri:       pointy.GetPointer(v.AttachmentSource),
					Url:       pointy.GetPointer(v.AttachmentImageURL),
					Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
					Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
					AltText:   pointy.GetPointer(v.AttachmentImageAlt),
					Meta:      pointy.GetPointer(v.AttachmentImageMeta),
				})
			}
		}

		topicFilterMap := make(map[string]map[string][]any)
		topicFilterMap[model.ForumTopicColumns.TopicID] = map[string][]any{
			"in": tids,
		}
		topicList, _, err := l.svcCtx.Topic.GetList(l.ctx, model.M{}, -1, topicFilterMap)
		if err != nil {
			return nil, err
		}

		idTopicMap := make(map[uint64]*forum.TopicInfo)
		if len(topicList) > 0 {
			for _, v := range topicList {
				idTopicMap[v.TopicID] = &forum.TopicInfo{
					Id:           pointy.GetPointer(v.TopicID),
					ForumId:      pointy.GetPointer(v.ForumID),
					AuthorId:     pointy.GetPointer(v.TopicAuthorID),
					Title:        pointy.GetPointer(v.Title),
					Slug:         pointy.GetPointer(v.Slug),
					Status:       pointy.GetPointer(uint32(v.TopicStatus)),
					Sticky:       pointy.GetPointer(uint32(v.Sticky)),
					PostCount:    pointy.GetPointer(uint32(v.PostCount)),
					CommentCount: pointy.GetPointer(uint32(v.CommentCount)),
					CreatedAt:    pointy.GetPointer(modelx.FormatTime(v.TopicDate, "")),
					UpdatedAt:    pointy.GetPointer(modelx.FormatTime(v.TopicModifiedDate, "")),
					Author: &forum.ForumAuthorInfo{
						Id:        pointy.GetPointer(v.TopicAuthorID),
						Name:      pointy.GetPointer(v.TopicAuthorNickname),
						Email:     pointy.GetPointer(v.TopicAuthorEmail),
						Avatar:    pointy.GetPointer(v.TopicAuthorAvatar),
						Ip:        pointy.GetPointer(v.TopicAuthorIP),
						Level:     pointy.GetPointer(uint32(v.TopicAuthorRankID)),
						Anonymous: pointy.GetPointer(uint32(v.TopicAuthorAnonymous)),
					},
				}
			}
		}

		for _, v := range res {
			var media []*forum.ForumMediaInfo
			if ms, ok := idMediaMap[v.PostID]; ok {
				media = ms[:]
			}
			var topic *forum.TopicInfo
			if tv, ok := idTopicMap[v.TopicID]; ok {
				topic = tv
			}
			resp.List = append(resp.List, &forum.PostInfo{
				Id:            pointy.GetPointer(v.PostID),
				ForumId:       pointy.GetPointer(v.ForumID),
				AuthorId:      pointy.GetPointer(v.PostAuthorID),
				TopicId:       pointy.GetPointer(v.TopicID),
				ParentId:      pointy.GetPointer(v.ParentID),
				ContentHtml:   pointy.GetPointer(v.PostContent),
				Content:       pointy.GetPointer(v.PostContent),
				Status:        pointy.GetPointer(uint32(v.PostStatus)),
				Sticky:        pointy.GetPointer(uint32(v.Sticky)),
				CommentStatus: pointy.GetPointer(uint32(v.CommentStatus)),
				CommentCount:  pointy.GetPointer(uint32(v.CommentCount)),
				PhotoCount:    pointy.GetPointer(uint32(v.PhotoCount)),
				CreatedAt:     pointy.GetPointer(modelx.FormatTime(v.PostDate, "")),
				UpdatedAt:     pointy.GetPointer(modelx.FormatTime(v.PostModifiedDate, "")),
				AverageRating: pointy.GetPointer(moneyx.ParseStar(v.AverageRating, 1)),
				Author: &forum.ForumAuthorInfo{
					Id:        pointy.GetPointer(v.PostAuthorID),
					Name:      pointy.GetPointer(v.PostAuthorNickname),
					Email:     pointy.GetPointer(v.PostAuthorEmail),
					Avatar:    pointy.GetPointer(v.PostAuthorAvatar),
					Ip:        pointy.GetPointer(v.PostAuthorIP),
					Level:     pointy.GetPointer(uint32(v.PostAuthorRankID)),
					Anonymous: pointy.GetPointer(uint32(v.PostAuthorAnonymous)),
				},
				Media: media,
				Topic: topic,
			})
		}
	}

	return resp, nil
}
